package com.michael.demos.base.java.arithmetic;

/**
 * 类功能描述:
 * <pre>
 *   雪花算法
 *   1(0)+6(业务码)+41(时间戳)+8(机器码)+8(序号)
 * </pre>
 *
 * @author Michael
 * @version 1.0
 * @date 2021/05/21 12:43
 */
public class SnowFlake1 {

    /** 起始的时间戳 2021-5-20 13:14:20 */
    private final static long START_TIMESTAMP = 1621487660000L;

    //private final static long START_TIMESTAMP = 12028460000L;
    //private final static long START_TIMESTAMP = 1305868460000L;

    /**
     * 每一部分占用的位数
     */
    private final static long BIZ_BIT = 6;
    private final static long TIME_BIT = 41;
    private final static long WORKER_BIT = 8;
    private final static long SEQUENCE_BIT = 8;

    /**
     * 每一部分的最大值
     */
    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
    private final static long MAX_WORKER_NUM = -1L ^ (-1L << WORKER_BIT);
    private final static long MAX_BIZ_NUM = -1L ^ (-1L << BIZ_BIT);

    /**
     * 每一部分向左的位移
     */
    private final static long WORKER_LEFT = SEQUENCE_BIT;
    private final static long TIMESTAMP_LEFT = WORKER_LEFT + WORKER_BIT;
    private final static long BIZ_LEFT = TIMESTAMP_LEFT + TIME_BIT;

    /** 业务码 */
    private final long bizId;
    /** 机器码标识 */
    private final long workerId;

    /** 序列号 */
    private long sequence = 0L;

    /** 上一次时间戳 */
    private long lastTimeStamp = -1L;

    private long getNextMill() {
        long mill = getNewTimeStamp();
        while (mill <= lastTimeStamp) {
            mill = getNewTimeStamp();
        }
        return mill;
    }

    private long getNewTimeStamp() {
        return System.currentTimeMillis();
    }

    public SnowFlake1(long bizId, long workerId) {
        if (bizId > MAX_BIZ_NUM || bizId < 10) {
            throw new IllegalArgumentException("业务码配置错误");
        }
        if (workerId > MAX_WORKER_NUM || workerId < 0) {
            throw new IllegalArgumentException("机器码配置有误");
        }
        this.bizId = bizId;
        this.workerId = workerId;
    }

    /**
     * 产生下一个ID
     */
    public synchronized long nextId() {
        long currTimeStamp = getNewTimeStamp();
        if (currTimeStamp < lastTimeStamp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }

        if (currTimeStamp == lastTimeStamp) {
            //相同毫秒内，序列号自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //同一毫秒的序列数已经达到最大
            if (sequence == 0L) {
                currTimeStamp = getNextMill();
            }
        } else {
            //不同毫秒内，序列号置为0
            sequence = 0L;
        }

        lastTimeStamp = currTimeStamp;

        return bizId << BIZ_LEFT
               | (currTimeStamp - START_TIMESTAMP) << TIMESTAMP_LEFT
               | workerId << WORKER_LEFT
               | sequence;
    }

    public static void main(String[] args) {

        //SnowFlake1 snowFlake = new SnowFlake1(10,0);
        //for (int i = 0; i < (1 << 3); i++) {
        //    //10进制
        //    System.out.println(snowFlake.nextId());
        //}
        //
        //snowFlake = new SnowFlake1(63,0);
        //for (int i = 0; i < (1 << 3); i++) {
        //    //10进制
        //    System.out.println(snowFlake.nextId());
        //}

        long start = System.currentTimeMillis();
        SnowFlake1 snowFlake = new SnowFlake1(11, 1);
        for (int i = 0; i < 200000; i++) {
            //snowFlake.nextId();
            System.out.println(snowFlake.nextId());
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start );

        //for (int i = 10; i < 64; i++) {
        //    SnowFlake1 snowFlake = new SnowFlake1(i, 0);
        //    System.out.println(i + " -> " + snowFlake.nextId());
        //}
        //System.out.println("========================");
        //for (int i = 10; i < 64; i++) {
        //    SnowFlake1 snowFlake = new SnowFlake1(i, 255);
        //    System.out.println(i + " -> " + snowFlake.nextId());
        //}
    }
}
